package cn.lg.soar.mvc.aspect.log;

import cn.lg.soar.core.annotations.ApiClient;
import cn.lg.soar.mvc.log.OperationLogInterceptor;
import org.aopalliance.intercept.MethodInterceptor;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.StaticMethodMatcherPointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Method;

/**
 * 操作日志切面（基于日志配置表，动态控制）
 * @author luguoxiang
 * @date 2022/4/23
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@ConditionalOnProperty(name = "lg.mvc.log-mode", havingValue = "dynamic")
@Aspect
public class DynamicLogAspect {

    protected static final Logger LOGGER = LoggerFactory.getLogger(DynamicLogAspect.class);

    @Bean
    public MethodInterceptor operationLogInterceptor() {
        return new OperationLogInterceptor();
    }

    @Bean
    public Advisor customOperationLogAdvisor(MethodInterceptor operationLogInterceptor) {
        return new DefaultPointcutAdvisor(new CustomOperationLogPointcut(), operationLogInterceptor);
    }

    static class CustomOperationLogPointcut extends StaticMethodMatcherPointcut {

        @Override
        public boolean matches(Method method, Class<?> targetClass) {
            // 1. 判断类是否是 Controller
            if (targetClass.isAnnotationPresent(RestController.class) || targetClass.isAnnotationPresent(Controller.class)) {
                // 忽略内部接口控制器
                if (targetClass.isAnnotationPresent(ApiClient.class)) {
                    return false;
                }
                // 2. 判断方法是否是接口方法（是否有请求映射注解）
                return AnnotatedElementUtils.hasMetaAnnotationTypes(method, RequestMapping.class);
            }
            return false;
        }

    }

}
